home *** CD-ROM | disk | FTP | other *** search
- // Copyright (C) 2005 and onwards Google, Inc.
- // Author(s): fritz, darin
- //
- // This file provides logic for updating the GWA toolbar in response to events
- // generated from the GWA backend.
- //
- // For each <tabbrowser> instance, we create an instance of GIWebAccClient,
- // which we hook up to the <tabbrowser> so that it can receive load events
- // from the browser. We in turn receive events from the GIWebAccClient via
- // our GIWebAccObserver implementation.
- //
- // This file also implements all of the methods invoked from our XUL overlay.
- //
- // NOTE: Everything at global scope is prefixed with GWA_ to avoid conflicts
- // with other extensions that may overlay into browser.xul.
-
-
- /**
- * URLs corresponding to the items in the help menu
- */
- const GWA_kHelpGeneralURL =
- "http://webaccelerator.google.com/support";
- const GWA_kHelpPrivacyURL =
- "http://webaccelerator.google.com/privacy";
- const GWA_kHelpContactURL =
- "mailto:labs+webaccelerator@google.com";
- const GWA_kHelpAboutURL =
- "chrome://googlewebacc/content/gwa-about.html";
-
- /**
- * Name of the preference we use to store the fact that we've run before
- */
- const GWA_kInitializedPref = "google.webacc.ui.initialized";
-
- /**
- * Reference to the GIWebAccClient instance associated with the currently
- * loaded tabbrowser instance.
- */
- var GWA_client = null;
-
- /**
- * This is our implementation of GIWebAccObserver.
- */
- function GWA_WebAccObserver() {
- }
-
- GWA_WebAccObserver.prototype = {
- _active: 0,
- _tickerIndex: 0, // The index of the current speedometer image.
-
- /**
- * This method is called by XPConnect to determine the interfaces that we
- * support.
- */
- QueryInterface: function(iid) {
- if (!iid.equals(Components.interfaces.GIWebAccObserver) &&
- !iid.equals(Components.interfaces.nsISupports))
- throw Components.results.NS_ERROR_NO_INTERFACE;
- return this;
- },
-
- /**
- * This method is called by the client when a new page starts loading.
- */
- onStart: function() {
- this._active = true;
-
- var speedo = document.getElementById("gwa-speedo-button");
- if (speedo)
- speedo.removeAttribute("gwa-preloaded");
- },
-
- /**
- * This method is called by the client when a new page finishes loading.
- */
- onStop: function() {
- this._active = false;
- },
-
- /**
- * This method is called by the client when the tick count changes.
- *
- * @param tickCount
- * The current tick count.
- */
- onUpdateTicker: function(tickCount) {
- // Do not update ticker if we are in excluded mode.
- var excl = document.getElementById("gwa-exclude");
- if (excl && excl.checked)
- return;
-
- const MAX_TICKER_INDEX = 10;
-
- if (this._active) {
- var newIndex = tickCount;
- if (newIndex == this._tickerIndex)
- return;
-
- // Here, we attempt to smooth out the changes in the speedo by only
- // allowing it to step by only one tick per update.
- if (newIndex > this._tickerIndex) {
- if (++this._tickerIndex > MAX_TICKER_INDEX)
- this._tickerIndex = MAX_TICKER_INDEX;
- } else {
- if (--this._tickerIndex < 0)
- this._tickerIndex = 0;
- }
- } else {
- if (this._tickerIndex == 0)
- return;
- --this._tickerIndex;
- }
-
- // update the selected image
- var speedo = document.getElementById("gwa-speedo-button");
- if (speedo)
- speedo.setAttribute("gwa-speed", this._tickerIndex);
- },
-
- /**
- * This method is called by the client when the benefit value changes.
- *
- * @param benefit
- * The current benefit value in seconds. If this value is negative,
- * then it implies that GWA is still calibrating the benefit to the
- * user.
- */
- onUpdateBenefit: function(benefit) {
- const SECONDS_PER_DAY = 86400.0;
- const SECONDS_PER_HOUR = 3600.0;
- const SECONDS_PER_MINUTE = 60.0;
-
- // Present a user-friendly version of the benefit value.
- // TODO(darin): use the string bundle to support localization
- if (benefit == "tuning") {
- benefit = "Calibrating time saved...";
- } else if (benefit > SECONDS_PER_DAY) {
- benefit = (benefit / SECONDS_PER_DAY).toFixed(1) + " days saved";
- } else if (benefit > SECONDS_PER_HOUR) {
- benefit = (benefit / SECONDS_PER_HOUR).toFixed(1) + " hours saved";
- } else if (benefit > SECONDS_PER_MINUTE) {
- benefit = (benefit / SECONDS_PER_MINUTE).toFixed(1) + " minutes saved";
- } else if (benefit > 0) {
- benefit = (benefit - 0).toFixed(1) + " seconds saved";
- } else {
- benefit = "0.0 seconds saved";
- }
-
- var button = document.getElementById("gwa-status-button");
- if (button)
- button.setAttribute("label", benefit);
- },
-
- onUpdateExcludedState: GWA_updateExcludedState,
-
- onUpdateEnabledState: GWA_updateEnabledState,
-
- onMouseEnterAnchor: function(element) {
- var spec = element.href;
- if (spec == undefined)
- spec = element.getAttribute("href");
-
- if (GWA_getWebAccService().isPreloaded(spec)) {
- var speedo = document.getElementById("gwa-speedo-button");
- if (speedo)
- speedo.setAttribute("gwa-preloaded", "true");
- }
- },
-
- onMouseLeaveAnchor: function(element) {
- var speedo = document.getElementById("gwa-speedo-button");
- if (speedo)
- speedo.removeAttribute("gwa-preloaded");
- }
- };
-
- function GWA_ProgressListenerWrapper(listener) {
- this._listener = listener;
- }
-
- GWA_ProgressListenerWrapper.prototype = {
- _listener: null,
-
- QueryInterface: function(iid) {
- if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
- iid.equals(Components.interfaces.nsISupportsWeakReference) ||
- iid.equals(Components.interfaces.nsISupports))
- return this;
- throw Components.results.NS_ERROR_NO_INTERFACE;
- },
-
- onStateChange: function(web_progress, request, state_flags, status) {
- this._listener.onStateChange(web_progress, request, state_flags, status);
- },
-
- onProgressChange: function(web_progress, request, cur_self_progress,
- max_self_progress, cur_total_progress,
- max_total_progress) {
- this._listener.onProgressChange(web_progress, request,
- cur_self_progress, max_self_progress,
- cur_total_progress, max_total_progress);
- },
-
- onLocationChange: function(web_progress, request, location) {
- this._listener.onLocationChange(web_progress, request, location);
- },
-
- onStatusChange: function(web_progress, request, status, message) {
- this._listener.onStatusChange(web_progress, request, status, message);
- },
-
- onSecurityChange: function(web_progress, request, state) {
- this._listener.onSecurityChange(web_progress, request, state);
- },
-
- onLinkIconAvailable: function(browser, href) {}
- };
-
- /**
- * This is a helper function for getting the GWA service.
- *
- * @return The GIWebAccService service (a singleton).
- */
- function GWA_getWebAccService() {
- return Components.classes["@google.com/client/webacc-service;1"].
- getService(Components.interfaces.GIWebAccService);
- }
-
- /**
- * This is a helper function for getting the tabbrowser instance.
- *
- * @return The tabbrowser instance.
- */
- function GWA_getBrowser() {
- return document.getElementById("content");
- }
-
- /**
- * We want to place the GWA buttons next to the throbber by default, but the
- * throbber may appear in different places (depending on the platform or on
- * user configuration). So look at the two likely places it could be, and
- * return the ID of the toolbar that has the throbber.
- *
- * TODO what if they've removed the throbber?
- *
- * @returns String containing the name of the toolbar containing the
- * throbber box
- */
- function GWA_toolbarWithThrobber() {
- if (
- (document.getElementById("toolbar-menubar").hasAttribute("currentset") &&
- document.getElementById("toolbar-menubar").getAttribute("currentset")
- .indexOf("throbber-box") > -1) ||
- (document.getElementById("toolbar-menubar").hasAttribute("defaultset") &&
- document.getElementById("toolbar-menubar").getAttribute("defaultset")
- .indexOf("throbber-box") > -1) )
- return "toolbar-menubar";
-
- return "nav-bar";
- }
-
- /**
- * Adds the button to the appropriate toolbar.
- *
- * @param buttonId
- * String containing the id of the button we'd like to add
- * @param toolbarId
- * String containing the id of the toolbar to which to add the button
- * @param beforeId
- * String containing the id of the item currently in the toolbar to
- * place the button before (if it exists)
- */
- function GWA_addButtonToCurrentSet(buttonId, toolbarId, beforeId) {
- // Careful not to add the button if its already there for some reason
- var tb = document.getElementById(toolbarId);
- var currentSet = tb.getAttribute(tb.hasAttribute("currentset") ?
- "currentset" :
- "defaultset");
-
- var ids = currentSet.split(",");
- for (var i=0; i<ids.length; i++)
- if (ids[i] == buttonId)
- return;
-
- // Now actually add it.
- var i = currentSet.indexOf(beforeId);
- currentSet = (i > -1) ?
- (currentSet.slice(0, i) + buttonId + "," + currentSet.slice(i)) :
- (buttonId);
-
- // IMPORTANT! The currentSet setter actually makes the changes happen, but
- // it won't persist the changes without an update to the attribute value and
- // a call to document.persist.
- tb.setAttribute("currentset", currentSet);
- tb.currentSet = currentSet;
-
- document.persist(toolbarId, "currentset");
- }
-
- /**
- * Checks to see if this is the first time we're running, and if so adds the
- * button to the appropriate toolbar. We keep track of whether we've run
- * before using a preference.
- */
- function GWA_maybeAddButtonToToolbar() {
- var prefs = Components.classes["@mozilla.org/preferences;1"].
- getService(Components.interfaces.nsIPrefBranch);
-
- if (!prefs.prefHasUserValue(GWA_kInitializedPref)) {
- var toolbar = GWA_toolbarWithThrobber();
-
- // Be sure not to add these elements if they already exist elsewhere in the
- // document. This may happen if the user happens to reset our magic pref.
- if (!document.getElementById("gwa-status-button"))
- GWA_addButtonToCurrentSet("gwa-status-button", toolbar, "throbber-box");
- if (!document.getElementById("gwa-speedo-button"))
- GWA_addButtonToCurrentSet("gwa-speedo-button", toolbar, "throbber-box");
-
- prefs.setBoolPref(GWA_kInitializedPref, true);
- }
- }
-
- /**
- * This function is called once browser.xul has loaded and our overlay has been
- * processed. We attach this function to the "load" event of the global
- * window down below.
- */
- function GWA_init(event) {
- GWA_maybeAddButtonToToolbar();
-
- GWA_client = Components.classes["@google.com/client/webacc-client;1"].
- createInstance(Components.interfaces.GIWebAccClient);
- GWA_client.observer = new GWA_WebAccObserver();
-
- var wrapper = new GWA_ProgressListenerWrapper(GWA_client);
- GWA_getBrowser().addProgressListener(wrapper,
- Components.interfaces.nsIWebProgress.NOTIFY_STATE_NETWORK |
- Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);
-
- GWA_updateEnabledState(GWA_getWebAccService().isOn());
- }
-
- /**
- * This function is called when browser.xul is being unloaded.
- */
- function GWA_finish(event) {
- GWA_client.observer = null;
- GWA_client = null;
- }
-
- /**
- * This function is called by the UI to load a help topic or feature page.
- *
- * @param key
- * The string valued identifier for the URL to show.
- */
- function GWA_load(key) {
- var port = GWA_getWebAccService().port;
-
- // Because the value of port may change with every invocation, we generate
- // this table on each call. We don't care about optimizing this function's
- // performance since it is not called that frequently. Convenience wins.
- var URLs = {
- "help" : GWA_kHelpGeneralURL,
- "privacy" : GWA_kHelpPrivacyURL,
- "contact" : GWA_kHelpContactURL,
- "prefs" : "http://localhost:" + port + "/preferences",
- "stats" : "http://localhost:" + port + "/races"
- };
-
- GWA_getBrowser().loadURI(URLs[key], null, null);
- }
-
- /**
- * This function is called to update the excluded UI state.
- *
- * @param excluded
- * A boolean value indicating whether or not to show the current URI
- * (shown in the location bar) as excluded.
- */
- function GWA_updateExcludedState(excluded) {
- var excl = document.getElementById("gwa-exclude");
- if (excl) {
- excl.checked = excluded;
-
- // Sometimes the XBL binding may not have been applied yet, so the setter
- // may not take. If we don't do this here then the attribute might get out
- // of sync with the XBL property! Madness I tell you! :-/
- excl.setAttribute("checked", excluded);
- }
-
- var speedo = document.getElementById("gwa-speedo-button");
- if (speedo)
- speedo.setAttribute("gwa-excluded", excluded);
- }
-
- /**
- * This function is called to update the enabled UI state.
- *
- * @param enabled
- * A boolean value indicating whether or not to show GWA as enabled.
- */
- function GWA_updateEnabledState(enabled) {
- var speedo = document.getElementById("gwa-speedo-button");
- var button = document.getElementById("gwa-status-button");
-
- if (enabled) {
- if (speedo)
- speedo.removeAttribute("gwa-disabled");
- if (button) {
- button.removeAttribute("disabled");
- GWA_client.refreshBenefit();
- }
- } else {
- if (speedo)
- speedo.setAttribute("gwa-disabled", "true");
- if (button) {
- button.setAttribute("disabled", "true");
- button.setAttribute("label", "");
- }
- }
- }
-
- /**
- * This function is called by the UI to toggle exclusion of the current URI on
- * or off.
- */
- function GWA_toggleExcludeOnOff() {
- var excludeMenu = document.getElementById("gwa-exclude");
- GWA_updateExcludedState(!excludeMenu.checked);
-
- var currentURI = GWA_getBrowser().webNavigation.currentURI;
- GWA_getWebAccService().excludeURI(currentURI, excludeMenu.checked);
- }
-
- /**
- * This function is called by the UI to toggle GWA on or off.
- */
- function GWA_toggleOnOff() {
- var service = GWA_getWebAccService();
- var toggle = document.getElementById("gwa-toggle");
- var bundle = document.getElementById("gwa-strings");
-
- var label;
- if (toggle.getAttribute("gwa-mode") == "stop") {
- service.shutdownWarden();
- label = bundle.getString("Stopping");
- } else {
- service.startupWarden();
- label = bundle.getString("Starting");
- }
-
- var button = document.getElementById("gwa-status-button");
- if (button) {
- button.setAttribute("label", label);
- button.setAttribute("disabled", "true");
- }
- }
-
- /**
- * This function is called by the UI to update the GWA menu just before it is
- * shown to the user. We need to update the label on the on/off toggle
- * <menuitem> based on the state of the warden.
- */
- function GWA_updateMenu() {
- var prefs = document.getElementById("gwa-prefs");
- var stats = document.getElementById("gwa-stats");
- var excl = document.getElementById("gwa-exclude");
- var toggle = document.getElementById("gwa-toggle");
- var bundle = document.getElementById("gwa-strings");
-
- var enabled = GWA_getWebAccService().isOn();
- if (enabled) {
- prefs.removeAttribute("disabled");
- stats.removeAttribute("disabled");
- excl.removeAttribute("disabled");
- toggle.setAttribute("label", bundle.getString("StopText"));
- toggle.setAttribute("gwa-mode", "stop");
- } else {
- prefs.setAttribute("disabled", "true");
- stats.setAttribute("disabled", "true");
- excl.setAttribute("disabled", "true");
- toggle.setAttribute("label", bundle.getString("StartText"));
- toggle.setAttribute("gwa-mode", "start");
- }
-
- // Make sure that our toplevel UI is never out of sync with the menu items.
- GWA_updateEnabledState(enabled);
- }
-
- /**
- * This function is called by the UI to show the GWA about dialog.
- */
- function GWA_about() {
- openDialog(GWA_kHelpAboutURL, "", "chrome,modal,centerscreen");
- }
-
- addEventListener("load", GWA_init, false);
- addEventListener("unload", GWA_finish, false);
-